1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.data.ini; 12 public import hip.api.data.ini; 13 import hip.util.conv:to; 14 15 16 class IniFile : IHipIniFile 17 { 18 IniBlock[string] _blocks; 19 string path; 20 bool configFound = false; 21 bool _noError = true; 22 string[] errors; 23 24 bool noError() const{return _noError;} 25 ref IniBlock[string] blocks(){return _blocks;} 26 const(string[]) getErrors() const{return cast(const)errors;} 27 28 /** 29 * Simple parser for the .conf or .ini files commonly found. 30 */ 31 static IniFile parse(string content, string path = "") 32 { 33 IniFile ret = new IniFile(); 34 ret.path = path; 35 if(content != "") 36 ret.configFound = true; 37 38 for(int i = 0; i < content.length; i++) 39 { 40 char c = content[i]; 41 if(c == ';' || c == '#') 42 { 43 while(i < content.length && content[++i] != '\n'){} 44 continue; 45 } 46 else if(c == '[') 47 { 48 import hip.util.string : replaceAll, trim, splitRange; 49 import hip.util.algorithm:put; 50 string capture = ""; 51 while(i < content.length) 52 { 53 i++; 54 if(i >= content.length) 55 return ret; 56 else if(content[i] == ']') 57 break; 58 else 59 capture~=content[i]; 60 } 61 62 IniBlock block; 63 block.name = capture; 64 capture = ""; 65 //Read until finding a key. 66 while(++i < content.length && (c = content[i]) != '['){capture~=c;} 67 68 69 foreach(l; capture.splitRange("\n")) 70 { 71 l = l.trim; 72 if(l == "") 73 continue; 74 string k, v; 75 l.splitRange("=").put(&k, &v); 76 if(v == "") 77 { 78 ret.errors~= "No value for key '"~k~"'"; 79 ret._noError = false; 80 break; 81 } 82 string name = k.replaceAll(' ', ""); 83 block.vars[name] = IniVar(name, formatValue(v)); 84 } 85 ret.blocks[block.name] = block; 86 i--; 87 } 88 } 89 return ret; 90 } 91 92 IniVar* getIniVar(string varPath) 93 { 94 import hip.util.string:splitRange; 95 import hip.util.algorithm; 96 string accessorA, accessorB; 97 varPath.splitRange(".").put(&accessorA, &accessorB); 98 if(accessorB == "") 99 return null; 100 IniBlock* b = (accessorA in blocks); 101 if(b is null) 102 return null; 103 return (accessorB in *b); 104 } 105 } 106 107 /** 108 * Remove comments and spaces from the Value from KeyValue pair 109 */ 110 private string formatValue(string unformattedValue) 111 { 112 string ret; 113 foreach(ch; unformattedValue) 114 { 115 if(ch == '#' || ch == ';') //Remove comments 116 break; 117 if(ch == ' ') //Remove spaces for to!int and friends working correctly 118 continue; 119 ret~= ch; 120 } 121 return ret; 122 }